#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "header.h"
#include <errno.h>






int char_to_int(char c)
{
  if (c>96)
    return (int) c-97;
  else
    return (int) c-65;
}

int* string_to_int (char* buffer)
{
  int i = 0, j = 0;
  int cpt = nombre_caracteres_valides(buffer);
  int* buff = (int*) malloc (sizeof(int)*cpt);  
  i = 0;
  while( (i < strlen(buffer)) && (j < cpt))
    {
      if ((buffer[i]<123)&&(buffer[i]>96)) /* on est en minuscule et on veut passer en MAJUSCULE*/
	{
	  buff[j]=buffer[i]-97; /* 0<=buff[i]<=25 */
	  j++;
	}
      
      else 
	{
	  if( (buffer[i] < 91) && (buffer[i] > 64)) /* on est en MAJUSCULE et on veut passer en minuscule*/
	    {
	      buff[j]=buffer[i]-65; /* 0<=buff[i]<=25 */
	      j++;
	    }
	}
      i++;
    }
  
  return buff;
}

int nombre_caracteres_valides(char* buffer)
{
  int i, cpt = 0;
    for(i = 0; i < strlen(buffer); i++)
    {
      if (((buffer[i]<123)&&(buffer[i]>96)) ||  ((buffer[i] < 91) && (buffer[i] > 64)))
	{
	  cpt++;
	}
    }
    return cpt;
}


char int_to_char(int i, int flag)
{
  if (flag)
    return (char) i+97;
  else return (char) i+65;
}


char* int_to_string(int* buffer,int size, int flag)
{
  char* buff;
  int tmp;
  int i;
  if (flag==0)    /* si on veut des minuscules */
    tmp=97;
  else
    tmp=65;   /* si on veut des majuscules */



  buff = (char*) malloc (sizeof(char)*size);
  i=0;
  for (i=0;i<size;i++)
    {
      buff[i]=buffer[i]+tmp; /* 65<=buff[i]<=90 si flag=1 ou alors 97<=buff[i]<=122 si flag=0;*/
    }
  return buff;
}











int decalage(int c, int decalage)
{
  return ((c+decalage)%26);
}


char* cesar (char* buffer, int n)
{
  char* print;
  int * buff = string_to_int(buffer);
  int i=0;
  int taille = nombre_caracteres_valides(buffer);
  for (i=0;i<taille;i++)
    buff[i]=decalage(buff[i],n);

  print=int_to_string(buff,taille,1);
  free(buff);
  i=0;
  while ((print[i]<91) && (print[i]>64))
    {
      i++;
    }
  print[i]='\0';
  return print;
}




char* vigenere (char* buffer, char* key)
{
  char* print;
  int * buff = string_to_int(buffer);
  int* tab = string_to_int(key);
  int i=0,j=0,k=nombre_caracteres_valides(key);
  int taille = nombre_caracteres_valides(buffer);
  for (i=0;i<taille;i++)
    {
      buff[i]=decalage(buff[i],tab[j%k]);
      j++;
    }
  
  print=int_to_string(buff,taille,1);
  free(buff);
  free(tab);
  i=0;
  while ((print[i]<91) && (print[i]>64))
    {
      i++;
    }
  print[i]='\0';
  return print;
  
}



int decalage_d(int c, int decalage)
{
  if ((c-decalage)<0)
    return (26-abs(c-decalage));
  else 
    return (c-decalage);

}








char* d_cesar (char* buffer, int n)
{
  char* print;
  int * buff = string_to_int(buffer);
  int taille = nombre_caracteres_valides(buffer);
  int i=0;
  for (i=0;i<taille;i++)
    {
      buff[i]=decalage_d(buff[i],n);
    }
  
  print=int_to_string(buff,taille,0);
  
 
  free(buff);

  i=0;
  while ((print[i]<123) && (print[i]>96))
    {
      i++;
    }
  print[i]='\0';
  return print;
}



char* d_vigenere(char* buffer, char* key)
{
  char* print;
  int * buff = string_to_int(buffer);
  int* tab = string_to_int(key);
  int i=0,j=0,k=nombre_caracteres_valides(key);
  int taille = nombre_caracteres_valides(buffer);
  for (i=0;i<taille;i++)
    {
      buff[i]=decalage_d(buff[i],tab[j%k]);
      j++;
    }
  
  print=int_to_string(buff,taille,0);
  
  free(buff);
  free(tab);
  i=0;
  while ((print[i]<123) && (print[i]>96))
    {
      i++;
    }
  print[i]='\0';

  return print;
}




void affichage (char* string)    /* flag=0 si texte vient du terminal, 1 sinon (dans ce cas on évite l'affichage du \0 qui a du se faire modifier)*/
{
  int i;
  int cpt=0;
  for (i=0;i<strlen(string);i++)
    {
	{
	  printf("%c",string[i]);
	  cpt++;
	  if ((cpt%4)==0)
	    printf(" ");
	}
    }
  printf("\n");
  
}






char* extract (char* path)
{
  char* text;
  char* line;
  FILE* fichier = fopen(path, "r");
  if (!fichier)
    {
      fprintf(stderr,"Erreur ouverture fichier '%s'\n",path);
      exit(10);
    }  
  text = malloc(3000);
  line = malloc(1000);
  while((line = fgets(line, 1000, fichier)))
    {
      strcat(text, line);
    }
  /* text = fgets(text,3000,fichier);
     text[strlen(text)]='\0';*/
  fclose(fichier);
  return text;
}





void usage_cesar()
{
  fprintf(stderr,"\n\nCESAR\n\n\nNAME\n\tcesar - implémentation du chiffrement de Cesar\n\n\nSYNOPSIS\n\t> make all\n\n\t> [./]cesar -(COMMANDE1) -k (int)\n\n\nDESCRIPTION\n\tLe programme doit être utilisé avec deux commandes obligatoires.\n\n\tPour la première, il y a deux possibilités :\n\t\t-> -t [texte] : le texte saisi après l'option \"-t\" sera crypté par le programme et affiché à la fin de celui-ci.\n\t\t->");
fprintf(stderr," -f [nom_fichier] : cette option vous permet de donner le nom du fichier dans lequel le programme va récupérer le texte à traiter. Les caractères non reconnus sont filtrés automatiquement.\n\n\tPour la deuxième, la commande permet de renseigner la clé :\n\t\t");
  fprintf(stderr,"-> -k [texte] : le texte saisi après l'option \"-k\" sera la clé du chiffrement.\n\n\tOn peut également utiliser les programmes de chiffrement et déchiffrement simultanément avec un pipe '|'. Il faut alors seulement mettre en paramètre du déchiffrement la meme option de clé que celle du chiffrement..\n\n\nEXEMPLES\n\t./cesar -t \"J'aime les fruits au sirop\" -k 8\n\n\t./cesar -k 17 -f titi.txt\n\n\t./cesar -t \"ABCDE Fghije\" -k 5 | ./decryptage_cesar -k 5\n\n\n");
}



void usage_dcesar()
{
  fprintf(stderr,"\n\nDECRYPTAGE CESAR\n\n\nNAME\n\tdecryptage_cesar - implémentation du déchiffrement de Cesar\n\n\nSYNOPSIS\n\t> make all\n\n\t> [./]decryptage_cesar -(COMMANDE1) -k (int)\n\n\nDESCRIPTION\n\tLe programme doit être utilisé avec deux commandes obligatoires.\n\n\tPour la première, il y a deux possibilités :\n\t\t-> ");
  fprintf(stderr,"-t [texte] : le texte saisi après l'option \"-t\" sera crypté par le programme et affiché à la fin de celui-ci.\n\t\t-> -f [nom_fichier] : cette option vous permet de donner le nom du fichier dans lequel le programme va récupérer le texte à traiter. Les caractères non reconnus sont filtrés automatiquement.");
 fprintf(stderr,"\n\n\tPour la deuxième, la commande permet de renseigner la clé :\n\t\t-> -k [texte] : le texte saisi après l'option \"-k\" sera la clé du chiffrement.\n\n\nEXEMPLES\n\t./decryptage_cesar -t \"J'aime les fruits au sirop\" -k 8\n\n\t./decryptage_cesar -k 17 -f titi.txt\n\n\n");
}



void traitement_cesar(int argc, char** argv, int j, int cmp, int* key, char** text,int** flags)


{
  while (j<argc)

    {
     
      cmp=0;
      
      
      if (strcmp(argv[j],"-k")==0)  /* -k -> 0 */
	{
	  (*flags)[0]=1;
	  cmp=0;
	}
      else 
	{
	  
	  if (strcmp(argv[j],"-t")==0)    /* -t -> 1 */
	    {
	      (*flags)[1]=1;
	      cmp=1;
	    }
	  
	  else 
	    {
	      if (strcmp(argv[j],"-f")==0)  /* -f -> 2 */
		{
		  (*flags)[2]=1;
		  cmp=2;
		}
	      
	     
		      
	      else 
		{
		  
		  fprintf(stderr,"Vous avez saisi une option inconnue, '%s'.\n\n",argv[j]);
		  usage_cesar();
		  exit(2);
		}
	    }
	}
    
  
	
    
      switch(cmp)
	{
	  

	case 0 : 
	  {
	    (*key)=atoi(argv[j+1]);
	    j=j+2;
	    break;
	  }



	case 1 : 
	  {
	    (*text)=argv[j+1];
	    j=j+2;
	    break;
	  }


	case 2 : 
	  {
	    (*text) = extract(argv[j+1]);		    
	    j=j+2; 
	    break;
	  }


	default : 
	  {
	    break;
	  }
	}
    }
}






void usage_freqC()
{
  fprintf(stderr,"\n\nATTAQUE PAR FREQUENCE\n\n\nNAME\n\tfreqC - implémentation d'une attaque par fréquence sur chiffrement de Cesar\n\n\nSYNOPSIS\n\t> make all\n\n\t> [./]freqC -(COMMANDE1)\n\n\nDESCRIPTION\n\tLe programme doit être utilisé avec une commande au choix parmi :\n\t\t-> -t [texte] : le texte saisi après l'option \"-t\" sera crypté par le programme et affiché à la fin de celui-ci.\n\t\t");
  fprintf(stderr,"-> -f [nom_fichier] : cette option vous permet de donner le nom du fichier dans lequel le programme va récupérer le texte à traiter. Les caractères non reconnus sont filtrés automatiquement\n\n\nEXEMPLES\n\t./freqC -t \"J'aime les fruits au sirop\"\n\n\t./freqC -f titi.txt\n\n\n");
}






void traitement_freqC(char** argv, char** text,int** flags)


{


 
  if (strcmp(argv[1],"-t")==0)  /* -t -> 0 */
    {
      (*flags)[0]=1;
    }
  
  else 
    {
      
      if (strcmp(argv[1],"-f")==0)    /* -f -> 1 */
	{
	  (*flags)[1]=1;
	}	     
      
      else 
	{
	  
	  fprintf(stderr,"Vous avez saisi une option inconnue, '%s'.\n\n",argv[1]);
	  usage_freqC();
	  exit(2);
	}
    }
  

  
  
  if ((*flags)[1]==1)
    (*text) = extract(argv[2]);		     
  
}















void usage_vigenere ()
{
 fprintf(stderr,"\n\nVIGENERE\n\n\nNAME\n\tvigenere - implémentation du chiffrement de Vigenere\n\n\nSYNOPSIS\n\t> make all\n\n\t> [./]vigenere -(COMMANDE1) -(COMMANDE2)\n\n\nDESCRIPTION\n\tLe programme doit être utilisé avec deux commandes obligatoires.\n\n\tPour la première, il y a deux possibilités :\n\t\t-> -t [texte] : le texte saisi après l'option \"-t\" sera crypté par le programme et affiché à la fin de celui-ci.\n\t\t-> ");
  fprintf(stderr,"-f [nom_fichier] : cette option vous permet de donner le nom du fichier dans lequel le programme va récupérer le texte à traiter. Les caractères non reconnus sont filtrés automatiquement.\n\n\tPour la deuxième, les possibilités sont:\n\t\t-> -k [texte] : le texte saisi après l'option \"-k\" sera la clé du chiffrement.\n\t\t-> -kf [nom_fichier] : le contenu de \"nom_fichier\" sera la clé du chiffrement.\n\n\tOn peut également utiliser les programmes de chiffrement et déchiffrement");
  fprintf(stderr," simultanément avec un pipe '|'. Il faut alors seulement mettre en paramètre du déchiffrement la meme option de clé que celle du chiffrement.\n\n\nEXEMPLES\n\t./vigenere -t \"J'aime les fruits au sirop\" -k \"mamamia\"\n\n\t./vigenere -kf vigenere.txt -f titi.txt\n\n\t./vigenere -t \"Des engins mobiles... A ROULETTTTTTTTTTTTE\" -kf titi.txt\n\n\t./vigenere -t \"ABCDE Fghije\" -k \"toto\" | ./decryptage_vigenere -k \"toto\"\n\n\n");
}



void usage_dvigenere ()
{
 fprintf(stderr,"\n\nDECRYPTAGE VIGENERE\n\n\nNAME\n\tdecryptage_vigenere - implémentation du déchiffrement de Vigenere\n\n\nSYNOPSIS\n\t> make all\n\n\t> [./]decryptage_vigenere -(COMMANDE1) -(COMMANDE2)\n\n\nDESCRIPTION\n\tLe programme doit être utilisé avec deux commandes obligatoires.\n\n\tPour la première, il y a deux possibilités :\n\t\t-> -t [texte] : le texte saisi après l'option \"-t\" sera crypté par le programme et affiché à la fin de celui-ci.\n\t\t-> ");
  fprintf(stderr,"-f [nom_fichier] : cette option vous permet de donner le nom du fichier dans lequel le programme va récupérer le texte à traiter. Les caractères non reconnus sont filtrés automatiquement.\n\n\tPour la deuxième, les possibilités sont:\n\t\t-> -k [texte] : le texte saisi après l'option \"-k\" sera la clé du chiffrement.\n\t\t-> -kf [nom_fichier] : le contenu de \"nom_fichier\" sera la clé du chiffrement.\n\n\n");
  fprintf(stderr,"EXEMPLES\n\t./decryptage_vigenere -t \"J'aime les fruits au sirop\" -k \"mamamia\"\n\n\t./decryptage_vigenere -kf vigenere.txt -f titi.txt\n\n\t./decryptage_vigenere -t \"Des engins mobiles... A ROULETTTTTTTTTTTTE\" -kf titi.txt\n\n\n");
}


void traitement_vigenere(int argc, char** argv, int j, int cmp,int* index_text, char** text,char** keys,int** flags)
{

  while (j<argc)
    
    {
      
      cmp=0;
      
      
      if (strcmp(argv[j],"-k")==0)  /* -k -> 0 */
	{
	  (*flags)[0]=1;
	  cmp=0;
	}
      else 
	{
	  
	  if (strcmp(argv[j],"-t")==0)    /* -t -> 1 */
	    {
	      (*flags)[1]=1;
	      cmp=1;
	    }
	  
	  else 
	    {
	      if (strcmp(argv[j],"-f")==0)  /* -f -> 2 */
		{
		  (*flags)[2]=1;
		  cmp=2;
		}
	      
	      else 
		{
		  if (strcmp(argv[j],"-kf")==0)   /* -kf -> 3 */
		    {
		      (*flags)[3]=1;
		      cmp=3;
		    }
		 
		  else 
		    {
		      fprintf(stderr,"Vous avez saisi une option inconnue, '%s'.\n\n",argv[j]);
		      usage_vigenere();
		      exit(2);
		    }
		}
	    }
	}
      
      
  
	
    
      switch(cmp)
	{
	  

	case 0 : 
	  {
	    (*keys)=argv[j+1];
	    j=j+2;
	    break;
	  }



	case 1 : 
	  {
	    (*text)=argv[j+1];
	    j=j+2;
	    break;
	  }


	case 2 : 
	  {
	    (*text) = extract(argv[j+1]);		    
	    j=j+2; 
	    break;
	  }


	case 3 : 
	  {
	    (*keys) = extract(argv[j+1]);
	    j=j+2;
	    break;
	  }

	default : 
	  {
	    break;
	  }
	}
    }
  
}





void usage_machine ()
{
  fprintf(stderr,"\n\nMACHINE\n\n\nNAME\n\tmachine - simule le fonctionnement de la machine ENIGMA\n\n\nSYNOPSIS\n\t> make all\n\n\t> [./]machine int int int -(OPTIONS) int-int [3-10]\n\n\nDESCRIPTION\n\tLes trois premiers paramètres sont les entiers qui représenteront la position des rotors 1 à 3.\n\tIl y a trois options possibles après ces trois premiers paramètres.\n\t   ");
  fprintf(stderr,"-> -trace [texte] : le texte saisi après l'option \"-trace\" sera crypté par le programme lettre par lettre, avec affichage au fur et à mesure de la position des rotors.\n\t   -> -saisie : cette option vous permet de saisir caractère par caractère le texte que vous souhaitez crypter.\n\t   -> -print [texte] : le texte saisi après l'option \"-print\" sera crypté et affiché directement.\n");
  fprintf(stderr,"\tEnfin, vous devez indiquer les trois à dix permutations du plugboard en indiquant sans espace la première lettre, un séparateur puis la lettre avec laquelle elle permute.\n\n\n");
 fprintf(stderr,"EXEMPLES\n\n\t./machine C D E -trace \"J'aime les fruits au sirop!\" V-O R-Y J-K C-A \n\n\t./machine C H I -saisie T-Z A-X V-B L-I \n\n\t./machine G I S -print \"Des engins mobiles... A ROULETTTTTTTTTTTTTTTE\" A-B C-D E-F G-H I-J K-L M-N O-P Q-R S-T\n\n\n");

}





int traitement_machine(int argc, char** argv, int* choix, char** texte, Plugboard* plugb)
{

 

  int tmp; /* 0 si option 'saisie', 1 si option 'trace' ou 'print' */
  int parcours;
  int cpt=0;

  
  /*printf("Entree traitement\n");*/
  
  
  if (strcmp(argv[4],"-saisie")==0)
    {
      if ( (argc<8) || (argc>15))
	{
	  fprintf(stderr,"Erreur, nombre de paramètres incorrect (%d)\nRAPPEL : il faut au moins 3 permutations dans le plugboard et au plus 10.\n",argc);
	  usage_machine();
	  exit(1);
	}
      else 
	
	{
	  (*choix) = 1;
	  (*texte) = "";
	  tmp=0;
	}
     
    }

  else
    {
      if ( (strcmp(argv[4],"-trace")==0) || (strcmp(argv[4],"-print")==0) )	
	{
	  
	  if ( (argc<9) || (argc>16))
	    {
	      fprintf(stderr,"Erreur, nombre de paramètres incorrect (%d)\nRAPPEL : il faut au moins 3 permutations dans le plugboard et au plus 10.\n",argc);
	      usage_machine();
	      exit(1);
	    }
	  
	  
	  if (strcmp(argv[4],"-trace")==0)
	    {
	      (*choix) = 0;
	    }
	  
	  else 
	    {
	      (*choix) = 2;
	    }
	  (*texte) = oter_espaces(argv[5]);
	  tmp=1;
	}      
      
      else 
	{
	  fprintf(stderr,"Erreur, commande inconnue\n");
	  usage_machine();
	  exit(1);
	}
    }
  
  
  /*printf("Before switch OK\n");*/
  

  switch(tmp)
    {
    case 0 : 
      {
	parcours = (argc-(argc-5))+1;
	/* printf("nb elem : %d\n",parcours); */
	break;
      }    
    case 1 : 
      {
	parcours = (argc-(argc-6))+1;
	/* printf("nb elem : %d\n",parcours); */
	break;
      }
    default : 
      {
	break;
      }
    }


  /*  printf("Switch passé\n"); */

  for (tmp = parcours-1;tmp<argc;tmp++)
    {
      if (strlen(argv[tmp])!=3)
	{
	  fprintf(stderr,"Initialisation du plugboard incorrecte : \"%s\" : tmp = %d // argc = %d // cpt = %d\n",argv[tmp],tmp,argc,cpt);
	  usage_machine();
	  exit(2);
	}
      else 
	{
	  plugb->connexions[cpt][0]=char_to_int(argv[tmp][0]);
	  plugb->connexions[cpt][1]=char_to_int(argv[tmp][2]);
	  
	  cpt++;
	}
    }
      
  /* for (tmp=0;tmp<cpt;tmp++)
    {
      printf("%d -> %d\n",plugb->connexions[tmp][0],plugb->connexions[tmp][1]);
    }
  
  */
 

  return cpt;
  
  
}  







  

char* oter_espaces(char* x)
{

  char* v = malloc(3000);
  int i=0;
  int j=0;

  for (i=0;i<strlen(x);i++)
    {
     
      if ( ((x[i]>64) && (x[i]<91)) || ((x[i]>97) && (x[i]<124)))
	{
	  v[j]=x[i];
	  j++;
	}
    }
  
  v[j]='\0';

  return v;
}
